spring--aop 整合AspectJ

Spring AOP的实现已经臻于非常完善,而通过与AspectJ的整合使得AOP的使用简单且灵活。不论是XML还是注解,都实现了非侵入式的控制。而基于自动代理的基础上,整合的AspectJ也通过BeanPostProcessor扩展的方式实现细粒度的切面控制。XML方式通过以aop:config标签实现配置,注解方式则通过@Aspect声明切面类。两种方式底层的实现殊途同归,都是基于自动代理的基类AbstractAutoProxyCreator来完成。

Spring的组件通过XML配置进行注册以及初始化,其方式就是实现特定命名空间的NamespaceHandler接口,对于Spring+AspectJ的整合方式的XML配置,是从AopNamespaceHandler开始。其中注册了两个标签,config和aspectj-autoproxy,分别为XML配置的根标签,和注解方式的启用配置。

1
2
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

不同的解析器对应的处理最终实现了XML或注解方式的AspectJ AOP。

1.XML配置

先看一个XML配置的demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<!-- 原始对象 -->
<bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/>
<!-- 环绕增强对象 -->
<bean id="aspectjBrowserAroundAdvice" class="com.lcifn.spring.aop.advice.AspectJBrowserAroundAdvice"></bean>

<!-- aspectj aop 配置 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="browserPointcut" expression="execution(* com.lcifn.spring.aop.bean.*.*(..))"/>
<aop:aspect ref="aspectjBrowserAroundAdvice">
<aop:around method="aroundIntercept" pointcut-ref="browserPointcut"/>
</aop:aspect>
</aop:config>
</beans>

ConfigBeanDefinitionParser解析器用来处理XML配置,Spring的代码大多使用命名清晰的子方法来描述主结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ConfigBeanDefinitionParser.java

public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);

// 配置自动代理创建,基于AbstractAutoProxyCreator实现切面的发现和匹配
configureAutoProxyCreator(parserContext, element);

List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
// aop:pointcut标签解析
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
// aop:advisor标签解析
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
// aop:aspect标签解析
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}

parserContext.popAndRegisterContainingComponent();
return null;
}

parse方法的主要内容分为两部分,自动代理配置的创建以及代理XML配置的解析,可以从上面代码中很清晰的看出。

自动代理配置的创建

自动代理配置是基类AbstractAutoProxyCreator的子类AspectJAwareAdvisorAutoProxyCreator,来实现AspectJ相关的AOP的实现。其主要的类结构如下:

  • AbstractAutoProxyCreator:基于BeanPostProcessor扩展完成AOP代理的创建
  • AbstractAdvisorAutoProxyCreator:切面的发现和匹配
  • AspectJAwareAdvisorAutoProxyCreator:AspectJ相关支持

而configureAutoProxyCreator方法则完成了自动代理配置的初始化。

1
2
3
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

由工具类AopNamespaceUtils实现

1
2
3
4
5
6
7
8
9
10
11
AopNamespaceUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册AspectJ自动代理创建类
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 设置proxyTargetClass和exposeProxy属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}

对于AspectJ自动代理创建类的注册有一个优先级机制,即当前容器中已存在自动代理创建类的bean,则以优先级高的替换优先级低的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
AopConfigUtils.java

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 存在同名的AUTO_PROXY_CREATOR
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
// 传入的优先级高于原有的,则替换BeanDefinition的className
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 不存在同名,则创建新的BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

对于自动代理创建类的优先级,在Spring中定义了三个

1
2
3
4
5
6
// 基础版
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
// XML配置
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// 注解配置
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);

因而同时存在XML和注解时,注解的自动代理创建类会覆盖XML的。但AnnotationAwareAspectJAutoProxyCreator其实是AspectJAwareAdvisorAutoProxyCreator的子类,在查询候选Advisor时,会先调用父类的方法获取XML配置中的Advisor。

另外aop:config可以配置proxy-target-class和expose-proxy,通过useClassProxyingIfNecessary方法设置到AspectJAwareAdvisorAutoProxyCreator的BeanDefinition的属性中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
AopNamespaceUtils.java

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

代理XML配置的解析

注册完自动代理创建类,接下来就是aop的具体配置。常用的一般是aop:pointcutaop:aspect两个标签,aop:advisor通常在外部aop:config外存在advice配置时使用。

对pointcut的解析比较简单,就是获取id及expression属性,然后创建pointcut的BeanDefinition。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ConfigBeanDefinitionParser.java

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
String expression = pointcutElement.getAttribute(EXPRESSION);

AbstractBeanDefinition pointcutDefinition = null;

try {
this.parseState.push(new PointcutEntry(id));
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}

parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}

return pointcutDefinition;
}

主要来看下对aspect的解析,在aop:aspect中的有两类子标签,一种是pointcut切入点的配置,一种是advice增强的配置,而advice又分为前置增强,后置增强,环绕增强等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
ConfigBeanDefinitionParser.java	

private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);

try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();

// 解析引入增强
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}

// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 解析advice增强,组装BeanDefinition
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}

AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);

// 解析pointcut标签
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}

parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}

对advice增强的解析parseAdvice方法是核心部分,而其返回的是组装好的Advisor切面BeanDefinition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
ConfigBeanDefinitionParser.java	

private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

// create the method factory bean
// 用来获取切面类中的增强方法Method对象的工厂bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);

// create instance factory definition
// 用来获取切面类对象的工厂bean
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);

// register the pointcut
// 根据不同的增强标签创建不同的增强BeanDefinition
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);

// configure the advisor
// 创建AspectJPointcutAdvisor,封装上面创建的AdviceBeanDefinition
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}

// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

return advisorDefinition;
}
finally {
this.parseState.pop();
}
}

此方法中先创建了两个合成的BeanDefinition,一个为增强方法的工厂,一个为切面对象的工厂,用来最终通过反射调用时使用。而后根据不同的advice标签(aop:before,aop:after-returning等)创建相应的增强BeanDefinition,最后使用AspectJPointcutAdvisor封装增强BeanDefinition然后返回。

再来看看对advice标签的解析createAdviceDefinition方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

// 创建advice的BeanDefinition,获取advice对应的Class对象
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));

adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

// after-returning的returning属性解析
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
// after-throwing的throwing属性解析
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
// arg-names参数昵称属性解析
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}

// 创建AdviceBeanDefinition构造函数
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
// 构造函数设置增强方法工厂
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

// 构造函数设置pointcut
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}

// 构造函数设置切面对象工厂
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

return adviceDefinition;
}

不同的Advice标签对应不同的Advice类,但都继承同一个基类AbstractAspectJAdvice。AbstractAspectJAdvice定义了构造函数

1
2
3
public AbstractAspectJAdvice(
Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
}

创建Advice的BeanDefinition时,即按照此构造函数组装BeanDefinition中的ConstructorArgumentValues属性。

而对于不同的advice则通过getAdviceClass方法匹配对应的Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}

至此,每个Advice都设置了切入点,切面类以及增强方法,再由AspectJPointcutAdvisor对Advice进行封装,在每个bean初始化之后,AspectJAwareAdvisorAutoProxyCreator的基类AbstractAutoProxyCreator实现了BeanPostProcessor扩展,查询所有的匹配bean的Advisor,并创建bean对应的Proxy代理,在方法真正执行时,触发其相应的Advice执行。

2.注解配置

不论是通过<aop:aspectj-autoproxy/>还是@EnableAspectJAutoProxy配置的AspectJ注解支持,都是通过AnnotationAwareAspectJAutoProxyCreator支撑对AspectJ相关注解的解析和注册。注册AnnotationAwareAspectJAutoProxyCreator的过程是通过AspectJAutoProxyRegistrar实现的。

AnnotationAwareAspectJAutoProxyCreator继承AnnotationAwareAspectJAutoProxyCreator,并覆盖了查询所有候选Advisor的方法findCandidateAdvisors。基于此方法对@Aspect的切面类进行解析,并生成相应Advisor对象返回。

1
2
3
4
5
6
7
8
9
10
11
AnnotationAwareAspectJAutoProxyCreator.java

protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 调用父类方法,兼容XML和注解并存
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 解析注解方式的切面
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}

核心操作交由BeanFactoryAspectJAdvisorsBuilder类的buildAspectJAdvisors方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
BeanFactoryAspectJAdvisorsBuilder.java

public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;

synchronized (this) {
// 缓存aspectName
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
// 获取所有spring容器中的bean
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this
// case they would be cached by the Spring container but would not
// have been weaved
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 有@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 创建Aspect实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 根据Aspect实例工厂获取所有Advisor对象
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 加入缓存
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}

if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
// 如果aspectNames不为空,则从缓存中获取对应的Advisor
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}

核心方法是根据Aspect实例工厂获取所有Advisor对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
ReflectiveAspectJAdvisorFactory.java

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
final String aspectName = maaif.getAspectMetadata().getAspectName();
validate(aspectClass);

// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 懒加载装饰类封装Aspect实例工厂
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(maaif);

final List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
// 返回有Advice类型(@Before,@AfterReturning等)的注解方法生成的Advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}

// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果切面类设置了懒加载,在advisor链最前增加一个前置拦截器,用来初始化切面类
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}

// Find introduction fields.
// 查询引入增强
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}

return advisors;
}

getAdvisor方法执行具体的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ReflectiveAspectJAdvisorFactory.java

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
int declarationOrderInAspect, String aspectName) {

validate(aif.getAspectMetadata().getAspectClass());

// 获取pointcut切入点expression表达式对象
AspectJExpressionPointcut ajexp =
getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
if (ajexp == null) {
return null;
}
// 实例化Advisor对象,支持懒加载策略
return new InstantiationModelAwarePointcutAdvisorImpl(
this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}

Advisor对应的Advice对象的实例化实际发生在InstantiationModelAwarePointcutAdvisorImpl的构造方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

this.declaredPointcut = ajexp;
this.method = method;
this.atAspectJAdvisorFactory = af;
this.aspectInstanceFactory = aif;
this.declarationOrder = declarationOrderInAspect;
this.aspectName = aspectName;

if (aif.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut =
Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
this.lazy = true;
}
else {
// A singleton aspect.
// 实例化Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
this.pointcut = declaredPointcut;
this.lazy = false;
}
}

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.atAspectJAdvisorFactory.getAdvice(
this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}

通过ReflectiveAspectJAdvisorFactory工厂类完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);

// 获取方法上的AspectJ注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}

// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}

if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}

AbstractAspectJAdvice springAdvice;

// 根据不同AspectJ注解生成对应的Advice对象
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method " + candidateAdviceMethod);
}

// Now to configure the advice...
// 配置Advice对象
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrderInAspect);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}

至此,注解方式的切面类中的每个Advice方法生成对应的Advice对象,并被InstantiationModelAwarePointcutAdvisor实现类封装然后返回。

相比于XML配置的方式,注解方式的Advisor不会生成BeanDefinition注册到Spring容器中,而是直接返回到Advisor集合中,并以aspectName的方式进行缓存防止重复生成及性能优化。

对于Spring+AspectJ的方式,其主要操作都在于Advisor的解析和生产,底层通过Spring自动代理的方式被Spring容器初始化bean时调用。而AOP代理则是使用ProxyFactory,根据不同配置决定JDK或CGLIB的方式来生成。

备注

  1. 原创:Spring源码-AOP(七)-整合AspectJ
  2. Spring Import 三种用法与源码解读